package com.tools.s7.recycler;

import android.support.annotation.NonNull;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.tools.s7.R;
import com.tools.s7.recycler.holder.BaseHolder;
import com.tools.s7.recycler.holder.BaseViewHolder;
import com.tools.s7.recycler.holder.ErrorViewHolder;
import com.tools.s7.recycler.holder.FooterViewHolder;
import com.tools.s7.recycler.holder.LoadErrorHolder;
import com.tools.s7.recycler.holder.LoadViewHolder;
import com.tools.s7.recycler.listener.Recycler;
import com.tools.s7.recycler.utils.BaseRecyclerCode;

import java.util.ArrayList;
import java.util.List;

public abstract class BaseStaggeredAdapter<T> extends RecyclerView.Adapter<BaseHolder> {

    @Override
    public BaseHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        if (viewType == BaseRecyclerCode.TYPE_ITEM) {
            View view = getView(parent, getLayoutId());
            return new BaseViewHolder(view);
        }else if (viewType == BaseRecyclerCode.TYPE_LOAD) {
            View view = getView(parent, getLoadId());
            return new LoadViewHolder(view);
        } else if (viewType == BaseRecyclerCode.TYPE_FOOTER) {
            View view = getView(parent, getFooderId());
            return new FooterViewHolder(view);
        }  else {
            View view = getView(parent, getLoadErrorId());
            return new LoadErrorHolder(view);
        }
    }

    private View getView(ViewGroup parent, int id) {
        return LayoutInflater.from(parent.getContext()).inflate(id, parent, false);
    }

    @Override
    public void onBindViewHolder(BaseHolder holder, int position) {

        holder.setRealPosition(position);

        initListener(holder);
        if (holder instanceof BaseViewHolder) {
            initClickListener((BaseViewHolder) holder, datas.get(position));
            ((BaseViewHolder) holder).setData(datas.get(position));
            bindData((BaseViewHolder) holder, position, datas.get(position));
        }
        if (holder instanceof LoadViewHolder) {
            bindLoad((LoadViewHolder) holder, position);
        }
        if (holder instanceof FooterViewHolder) {
            bindFooter((FooterViewHolder) holder, position);
        }
        if (holder instanceof LoadErrorHolder) {
            bindLoadError((LoadErrorHolder) holder, position);
        }
    }

    @Override
    public int getItemCount() {
        if (isLegal() && !isFirst) {
            return datas == null ? 1 : datas.size() + 1;
        }
        return datas == null ? 0 : datas.size();
    }

    public boolean isLegal() {
        return (isLoad || isFooter || isLoadError);
    }

    @Override
    public int getItemViewType(int position) {

        if (isLoad && position + 1 == getItemCount()) {
            return BaseRecyclerCode.TYPE_LOAD;
        }
        if (isFooter && position + 1 == getItemCount()) {
            return BaseRecyclerCode.TYPE_FOOTER;
        }
        if (isLoadError && position + 1 == getItemCount()) {
            return BaseRecyclerCode.TYPE_LOAD_ERROR;
        }
        return BaseRecyclerCode.TYPE_ITEM;
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return isFooter(position) ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(@NonNull BaseHolder holder) {
        super.onViewAttachedToWindow(holder);
        if (isStaggeredGridLayout(holder)) {
            handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
        }
    }

    private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
            return true;
        }
        return false;
    }

    protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
        if ( isFooter(position)){
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams)
                    holder.itemView.getLayoutParams();
            p.setFullSpan(true);
        }
    }

    private boolean isFooter(int position) {
        if (position == datas.size()){
            return true;
        }
        return false;
    }

    protected abstract int getLayoutId();

    protected int getLoadId() {
        return R.layout.tools_load;
    }

    protected int getLoadErrorId() {
        return R.layout.tools_load_error;
    }

    protected int getFooderId() {
        return R.layout.tools_footer;
    }

    protected abstract void bindData(BaseViewHolder holder, int position, T data);

    protected void bindLoadError(LoadErrorHolder holder, int position) {

    }

    protected void bindFooter(FooterViewHolder holder, int position) {

    }

    protected void bindLoad(LoadViewHolder holder, int position) {

    }


    protected List<T> datas;
    private boolean isFirst = true;
    private boolean isAadditional = true;
    private boolean isLoad = true;
    private boolean isFooter = false;
    private boolean isLoadError = false;
    private int num = 100;
    protected Recycler.OnLoadingListener loadingListener;

    public BaseStaggeredAdapter setAadditional(boolean aadditional) {
        isAadditional = aadditional;
        return this;
    }

    public BaseStaggeredAdapter setPageSize(int num) {
        this.num = num;
        return this;
    }

    public BaseStaggeredAdapter setLoad(boolean load) {
        if (isAadditional) {
            isLoad = load;
        } else {
            isLoad = false;
        }
        return this;
    }

    public BaseStaggeredAdapter setFooter(boolean footer) {
        if (isAadditional) {
            isFooter = footer;
        } else {
            isFooter = false;
        }
        return this;
    }

    public BaseStaggeredAdapter setLoadError(boolean loadError) {
        if (isAadditional) {
            isLoadError = loadError;
            isLoad = !isLoadError;
        } else {
            isLoadError = false;
            isLoad = false;
        }
        notifyDataSetChanged();
        return this;
    }

    public BaseStaggeredAdapter setLoadingListener(Recycler.OnLoadingListener loadingListener) {
        this.loadingListener = loadingListener;
        return this;
    }

    protected Recycler.OnCheckedChangeListener mCheckedChange;
    protected Recycler.OnClickListener<T> mClick;
    protected Recycler.OnItemClickListener<T> mItemClick;
    protected Recycler.OnItemLongClickListener<T> mItemLongClick;

    protected void initClickListener(final BaseViewHolder holder, final T data) {
        if (mItemClick != null)
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mItemClick.onItemClick(holder.getRealPosition(), data);
                }
            });

        if (mItemLongClick != null) {
            holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    mItemLongClick.onItemLongClick(holder.getRealPosition(), data);
                    return false;
                }
            });
        }
    }

    protected void initListener(final BaseHolder holder) {

        if (holder instanceof LoadErrorHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    setLoadError(false);
                }
            });
        }

        if (holder instanceof LoadViewHolder) {
            if (loadingListener != null) {
                loadingListener.onLoading();
            }
        }

        if (holder instanceof ErrorViewHolder) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (loadingListener != null) {
                        loadingListener.onReload();
                    }
                }
            });
        }

    }

    public BaseStaggeredAdapter setCheckedChange(Recycler.OnCheckedChangeListener<T> mCheckedChange) {
        this.mCheckedChange = mCheckedChange;
        return this;
    }

    public BaseStaggeredAdapter setClick(Recycler.OnClickListener<T> mClick) {
        this.mClick = mClick;
        return this;
    }

    public BaseStaggeredAdapter setItemClick(Recycler.OnItemClickListener<T> mItemClick) {
        this.mItemClick = mItemClick;
        return this;
    }

    public BaseStaggeredAdapter setItemLongClick(Recycler.OnItemLongClickListener<T> mItemLongClick) {
        this.mItemLongClick = mItemLongClick;
        return this;
    }

    public BaseStaggeredAdapter() {
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
    }

    public BaseStaggeredAdapter(List<T> datas) {
        this.datas = datas;
    }

    public void onRefresh(List<T> datas) {
        initFlag();
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
        this.datas.clear();
        if (datas != null) {
            this.datas.addAll(datas);
        }
        isLoad();
        notifyDataSetChanged();
//        notifyItemRangeChanged(0, getItemCount());
    }

    private void initFlag() {
        isFirst = false;
        if (isAadditional) {
            isLoad = true;
            isLoadError = false;
            isFooter = false;
        } else {
            isLoad = false;
            isLoadError = false;
            isFooter = false;
        }
    }

    private void isLoad() {
        if (!isAadditional) {
            return;
        }
        isLoadError = false;
        if (datas.size() % num == 0 && datas.size() > 0) {
            isLoad = true;
            isFooter = false;
        } else {
            isLoad = false;
            isFooter = true;
        }
    }

    public void addDatas(List<T> datas) {
        if (datas != null) {
            this.datas.addAll(datas);
//            notifyDataSetChanged();
            isLoad();
            notifyItemRangeInserted(getItemCount(), datas.size());
        }
    }

    public void addData(T data) {
        if (data != null) {
            int start = this.datas.size();
            this.datas.add(data);
//            notifyDataSetChanged();
            notifyItemRangeInserted(start, 1);
        }
    }

    public void onReplace(int position, T data) {
        if (position < this.datas.size() && data != null) {
            this.datas.set(position, data);
            notifyDataSetChanged();
        }
    }

    public void onRemove(int position) {
        if (position < this.datas.size()) {
            this.datas.remove(position);
            notifyDataSetChanged();
        }
    }

    public List<T> getDatas() {
        return datas;
    }
}
